
package com.scs.application.modules.report.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.parser.SqlInfo;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.DialectFactory;
import com.baomidou.mybatisplus.extension.plugins.pagination.DialectModel;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.plugins.pagination.dialects.MySqlDialect;
import com.baomidou.mybatisplus.extension.toolkit.SqlParserUtils;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.scs.application.consts.GlobalConsts;
import com.scs.application.core.exception.BusinessException;
import com.scs.application.core.query.QueryContext;
import com.scs.application.core.query.QueryContextHolder;
import com.scs.application.core.query.QueryGenerator;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.utils.*;
import com.scs.application.modules.base.util.CommonService;
import com.scs.application.modules.report.consts.DictConsts;
import com.scs.application.modules.report.entity.ChartField;
import com.scs.application.modules.report.entity.Config;
import com.scs.application.modules.report.entity.GridField;
import com.scs.application.modules.report.entity.PreCondition;
import com.scs.application.modules.report.handler.BeforeReport;
import com.scs.application.modules.report.handler.ParamHandler;
import com.scs.application.modules.report.mapper.ConfigMapper;
import com.scs.application.modules.report.service.ChartFieldService;
import com.scs.application.modules.report.service.ConfigService;
import com.scs.application.modules.report.service.GridFieldService;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.io.Serializable;
import java.sql.ResultSetMetaData;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 报表配置 service 实现
 */
@Slf4j
@Service
public class ConfigServiceImpl extends BaseServiceImpl<ConfigMapper, Config> implements ConfigService {
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Lazy
    @Autowired
    private  GridFieldService reportGridFieldService;
    @Lazy
    @Autowired
    private  ChartFieldService reportChartFieldService;
    @Lazy
    @Autowired
    private  DataSource dataSource;
    private final String[] IgnoreUpCaseArr = new String[]{"desc", "group", "asc", "by", "order"};
    @Autowired
    private JdbcTemplate jdbcTemplate;


    private List<ParamHandler> paramHandlers;

    @Autowired(required = false)
    public void setParamHandlers(List<ParamHandler> paramHandlers) {
        this.paramHandlers = paramHandlers;
    }

    @Override
    public boolean removeCascadeById(Serializable id) {
        reportGridFieldService.remove(Wrappers.<GridField>query().eq("report_id", id));
        reportChartFieldService.remove(Wrappers.<ChartField>query().eq("report_id", id));
        return super.removeById(id);
    }


    @Override
    public Map<String, Object> fetchData(String id, Map<String, Object> params) throws Exception {
        return this.fetchData(id, true, params);
    }

    //获取配置表头
    @Override
    public List<GridField> getGridFields(String id) {
        Config config = this.getById(id);
        if (config == null) {
            throw new BusinessException("报表参数错误，请确认");
        }
        return reportGridFieldService.list(Wrappers.<GridField>query().eq("report_id", config.getId()).orderByAsc("sort"));
    }

    /**
     * 自动填充表格列
     *
     * @param config
     * @return
     */
    @Override
    public Boolean autoGridFields(Config config) throws Exception {
        List<String> columns = getDataColumns(config, new HashMap<>());
        if (columns != null) {
            List<GridField> addGridFields = Lists.newArrayList();
            List<GridField> existGridFields = getGridFields(config.getId());
            columns.forEach(column -> {
                boolean exists = existGridFields == null ? false : existGridFields.stream().filter(Field -> Field.getField().equalsIgnoreCase(column))
                        .findFirst().isPresent();
                if (!exists) {
                    GridField gridField = new GridField();
                    gridField.setField(column)
                            .setAlign(DictConsts.REPORT_CONFIG_ALIGN_CENTER)
                            .setWidth("120")
                            .setLabel(column)
                            .setReportId(config.getId())
                            .setFlagShow(true)
                            .setFlagMergeCell(false);
                    addGridFields.add(gridField);
                }
            });
            if (addGridFields.size() > 0) { //设置sort值
                int sort = existGridFields == null || existGridFields.size() == 0 ? 0 : existGridFields.stream().map(GridField::getSort).max(Comparator.comparingInt(t -> t)).get();
                for (int i = 0; i < addGridFields.size(); i++) {
                    sort += 10;
                    addGridFields.get(i).setSort(sort);
                }
                return reportGridFieldService.saveBatch(addGridFields);
            }
        }
        return true;
    }

    //获取数据列
    @Override
    public List<String> getDataColumns(Config config, Map<String, Object> params) throws Exception {

        FetchResult result = fetchSqlData(config, false, params);
        if (result == null || result.getData() == null || result.getData().size() == 0) {
            return null;
        }
        Map<String, Object> firstData = result.getData().get(0);
        List<String> columns = new ArrayList(firstData.keySet());
        return columns;
    }

    @Override
    public Map<String, Object> fetchData(String id, boolean forcePaging, Map<String, Object> params) throws Exception {
        Config config = this.getById(id);
        ;
        if (config == null) {
            throw new BusinessException("报表参数错误，请确认");
        }
        Map<String, Object> resultMap = Maps.newHashMap();

       /* JSONArray types = config.getTypes();
        if (types == null) {
            types = new JSONArray();
        }*/
        String type = config.getType();
        // 包含表格字段
        List<GridField> gridFieldList = null;
        if (config.getFlagDynamicColumn() != null && config.getFlagDynamicColumn()) {
            gridFieldList = reportGridFieldService.list(Wrappers.<GridField>query().eq("report_id", config.getId()).orderByAsc("sort"));
        } else {
            gridFieldList = (List<GridField>) CacheUtils.get(CacheUtils.REPORt_GRID_FIELD_CACHE, id);
        }

        // 包含图表字段
        if (type.indexOf(DictConsts.REPORT_CONFIG_TYPES_LINE) != -1
                || type.indexOf(DictConsts.REPORT_CONFIG_TYPES_BAR) != -1
                || type.indexOf(DictConsts.REPORT_CONFIG_TYPES_PIE) != -1) {
            resultMap.put("chartFields", reportChartFieldService.list(Wrappers.<ChartField>query().eq("report_id", config.getId()).orderByAsc("sort")));
        }
        resultMap.put("config", config);
        String source = config.getSource();

        if (DictConsts.REPORT_CONFIG_SOURCE_SQL.equalsIgnoreCase(source)) {
            FetchResult result = fetchSqlData(config, forcePaging, params);
            if (config.getFlagDynamicColumn()) {
                //动态列字段
                gridFieldList = CommonService.reportGetDynamicColumns(config, params, gridFieldList, result.getData());
                //动态列数据
                result.setData(CommonService.reportGetDynamicData(config, gridFieldList, params, result.getData()));

                //动态列，数据会进行二次处理，所以记录数量需要覆盖
                if (result.getSumData() != null && result.getSumData().size() > 0){
                    long dataSize = result.getData() != null ? result.getData().size() : 0;
                    result.getSumData().get(0).put("sum",dataSize);
                    result.setTotalCount(dataSize);
                }
            }
            //            固定列展现二级表头
            if (config.getFlagFixedColumn()&&config.getFlagColumnSum()) {
                //相同的二级列,增加合计字段
                gridFieldList = CommonService.reportFixColumnParents(config,gridFieldList);
                //合计数据处理
                result.setData(CommonService.reportFixColumnParentData(config, gridFieldList, params, result.getData()));
            }
            resultMap.put("gridFields", gridFieldList);
            resultMap.put("data", result.getData());
            resultMap.put("sumData", result.getSumData());
            resultMap.put("totalCount", result.getTotalCount());
            resultMap.put("initDateQueryField", result.getInitDateQueryField());
            resultMap.put("initDateQueryStart", result.getInitDateQueryStart());
            resultMap.put("initDateQueryEnd", result.getInitDateQueryEnd());
            resultMap.put("initDateQuery", result.getInitDateQuery());
        } else if (DictConsts.REPORT_CONFIG_SOURCE_JSON.equalsIgnoreCase(source)) {
            resultMap.put("data", config.getDataJson());
        } else if (DictConsts.REPORT_CONFIG_SOURCE_URL.equalsIgnoreCase(source)) {

        }
        config.setDataSql(null).setDataJson(null).setDataUrl(null);
        return resultMap;
    }

    //获取前置条件的值
    private String getPreConditionValue(String conditionLeft) {
        String conditionRight = "";
        switch (conditionLeft) {
            case "deptId":
                conditionRight = UserUtils.currentUser().getDeptId();
                break;
            case "officeId":
                conditionRight = UserUtils.currentUser().getOfficeId();
                break;
            case "creator":
                conditionRight = UserUtils.currentUser().getId();
                break;
            case "warehouseId":
                conditionRight = WebUtils.getCurrentWarehouse();
                break;
            default:
                break;
        }
        return conditionRight;
    }

    //构建wrapper表达式
    private void buildEwExpress(QueryContext queryContext, String conditionMiddle, String ConditionLeft, String conditionRight) {
        switch (conditionMiddle) {
            case "eq":
                queryContext.getWrapper().eq(StringUtils.uncamelCase(ConditionLeft), conditionRight);
                break;
            case "like":
                queryContext.getWrapper().like(StringUtils.uncamelCase(ConditionLeft), conditionRight);
                break;
            case "ne":
                queryContext.getWrapper().ne(StringUtils.uncamelCase(ConditionLeft), conditionRight);
                break;
            default:
                break;
        }
    }

    /**
     * 解析SQL，获得数据
     *
     * @param config
     * @param forcePaging 强制分页
     * @param params
     * @return
     */
    @Override
    public FetchResult fetchSqlData(Config config, boolean forcePaging, Map<String, Object> params) throws Exception {
        //刷新临时表数据
        if (config.getFlagTmptable() != null && config.getFlagTmptable() && (!config.getFlagTmptableClear())) {
            CommonService.reportTempTable(config, true);
        }

        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.setFetchSize(0);
        jdbcTemplate.setMaxRows(0);

        NamedParamSqlUtils sqlUtils = new NamedParamSqlUtils();

        //处理sql
        String selectSql = beforeQuery(config, params);
        JSONArray perConditions = config.getPreConditions();

        QueryContext queryContext = QueryContextHolder.currentContext();

        if (StringUtils.isNotBlank((String) params.get("queryString")))
            queryContext.setWrapper(QueryGenerator.initQueryWrapper((String) params.get("queryString"), String.valueOf(params.get("orderString"))));
        if (params.get("ignorePreCondition") != null) { //忽略前置条件
            perConditions = null;
            params.remove("ignorePreCondition");
        }
        if (perConditions != null && perConditions.size() > 0) {
            List<PreCondition> preConditionList = perConditions.toJavaList(PreCondition.class);
            preConditionList.forEach(condition -> {
                if (StringUtils.isNotBlank(condition.getEwExpress())) {
                    if (StringUtils.isNotBlank(condition.getPreConditionsLeft())) { //按左边来
                        buildEwExpress(queryContext, condition.getPreConditionsMiddle(), condition.getPreConditionsLeft(), getPreConditionValue(condition.getPreConditionsLeft()));
                    } else { //纯根据表达式来构建,必须是.eq('key','value')格式，否则会解析不了
                        int pointPosition = condition.getEwExpress().indexOf('.'); //.所在位置
                        int letParenPosition = condition.getEwExpress().indexOf('（'); //左括号所在位置
                        int rightParenPosition = condition.getEwExpress().indexOf(')'); //右括号所在位置
                        int commaParenPosition = condition.getEwExpress().indexOf(','); //逗号所在位置

                        if (pointPosition < 0 || letParenPosition < 0 || rightParenPosition < 0 || commaParenPosition < 0) {

                        } else {
                            String ewMiddle = condition.getEwExpress().substring(pointPosition + 1, letParenPosition - pointPosition - 1);
                            String ewLeft = condition.getEwExpress().substring(letParenPosition + 1, commaParenPosition - letParenPosition - 1).replaceAll("\\'", "");
                            String ewRight = condition.getEwExpress().substring(commaParenPosition + 1, rightParenPosition - commaParenPosition - 1).replaceAll("\\'", "");
                            buildEwExpress(queryContext, ewMiddle, ewLeft, ewRight);
                        }
                    }
                }
            });
        }
        QueryWrapper wrapper = queryContext.getWrapper();

        List<GridField> gridFields = this.getGridFields(config.getId());
        List<GridField> dateFields = gridFields.stream().filter(s ->
                        GlobalConsts.DATEAREA.equals(s.getQueryType())
                ||
                        GlobalConsts.DATEAREAYEAR.equals(s.getQueryType())
                ||
                        GlobalConsts.DATEAREAMONTH.equals(s.getQueryType())
        ).collect(Collectors.toList());
        FetchResult result = new FetchResult();


        boolean isInit = Boolean.valueOf(params.get("isInit")+"");
        if (isInit && !dateFields.isEmpty() && StringUtils.isBlank((String) params.get("queryString"))) {
            GridField gridField = null;
            gridField = dateFields.stream().filter(s ->
                    s.getInitDateQuery() != null && s.getInitDateQuery() < 0
            ).findAny().orElse(dateFields.get(0));
            if (gridField != null && gridField.getInitDateQuery() != null) {
                Date date =null;
                String queryType = gridField.getQueryType();
                String startDate=null;
                String endDate=null;
                if (queryType.equals(GlobalConsts.DATEAREA) ) { //日期区间
                    if (gridField.getInitDateQuery() != 0) {
                        date = DateUtils.addDays(new Date(), gridField.getInitDateQuery());
                        startDate = DateUtils.format(date, "yyyy-MM-dd");
                        endDate = DateUtils.format(new Date(), "yyyy-MM-dd")+ " 23:59:59";
                    }
                }else if (queryType.equals(GlobalConsts.DATEAREAMONTH)) {//月份
                    date = DateUtils.addMonth(new Date(),gridField.getInitDateQuery());
                    startDate = DateUtils.format(date, "yyyy-MM")+"-01";
                    endDate = DateUtils.format(DateUtils.getLastDayOfMonth(date), "yyyy-MM-dd")+ " 23:59:59";
                    result.setInitDateQuery(DateUtils.format(date, "yyyy-MM"));
                }else if (queryType.equals(GlobalConsts.DATEAREAYEAR)) { //年份
                    date = DateUtils.addYear(new Date(),gridField.getInitDateQuery());
                    startDate = DateUtils.format(date, "yyyy")+"-01-01";
                    endDate = DateUtils.format(date, "yyyy")+"-12-31"+ " 23:59:59";
                    result.setInitDateQuery(DateUtils.format(date, "yyyy"));
                }
                if (startDate != null) {
                    wrapper = (QueryWrapper) wrapper.between(gridField.getField(), startDate, endDate);
                    result.setInitDateQueryStart(startDate);
                    result.setInitDateQueryEnd(endDate);
                    result.setInitDateQueryField(gridField.getField());
                }
            }

            if (gridField != null && gridField.getFlagMonthStart()) {
                wrapper = (QueryWrapper) wrapper.between(gridField.getField(), DateUtils.getMonthStartTimeStr(new Date()), DateUtils.getDateEndTimeStr(new Date()));
            }

        }
        params.putAll(queryContext.getParams());
        params.put("ew", wrapper);

        // 对查询SQL进行 模板渲染
        selectSql = FreeMarkers.renderString(selectSql, params);

        // 如果有使用 ew.customSqlSegment ，需要替换后再进行一次模板渲染
        selectSql = selectSql.replaceAll("#\\{(ew\\.paramNameValuePairs.*?)\\}", "'\\${$1}'");
        selectSql = FreeMarkers.renderString(selectSql, params);


        selectSql = sqlUtils.parseSql(selectSql);

        for (String strKey : IgnoreUpCaseArr) {
            selectSql = selectSql.replaceAll("(?i)" + strKey, strKey);
        }

//        selectSql = selectSql.replaceAll("\\s+", " "); //多的空格改成单空格
        Map<String, Object> handledParams = getHandledParams(sqlUtils, params);

        //查询合计列，不分页
        long countSum = 0;
        if (gridFields != null && gridFields.size() > 0) {
            result.setSumData(new ArrayList<Map<String, Object>>());

//            sumRow.put("sum",jdbcTemplate.queryForObject(sqlSum, Double.class));
//                    jdbcTemplate.query
//            result.sumData.add(sumRow);

            List<String> sumFieldList = new ArrayList<String>();
            sumFieldList.add("count(1) as countsum");
            for (GridField gridField : gridFields) {
                if (null == gridField.getFlagTotalRow() || !gridField.getFlagTotalRow()) continue;
                ;
                sumFieldList.add("sum(" + gridField.getField() + ") as " + gridField.getField());
            }
            //不显示顶部合计也不显示顶部合计
            if (config.getFlagTopSum() != null && config.getFlagTopSum() && config.getFlagBottomSum() != null && config.getFlagBottomSum() )  sumFieldList = null;
            if (sumFieldList != null && sumFieldList.size() > 0) {

                String sqlSum = selectSql;
                int orderByindex = sqlSum.lastIndexOf("order by");
                if (orderByindex != -1) {
                    String orderType = "asc";
                    if (sqlSum.lastIndexOf("desc") != -1) {
                        orderType = "desc";
                    }
                    int orderTypeIndex = sqlSum.lastIndexOf(orderType);
                    sqlSum = sqlSum.substring(0, orderByindex) + "    " + sqlSum.substring(orderTypeIndex + orderType.length(), sqlSum.length());
                }

                sqlSum = " select " + StringUtils.join(sumFieldList, ",") + " from (" + selectSql + ") t";

                Map<String, Object> sumMap = null;
//                sumMap = jdbcTemplate.queryForMap(sqlSum);
                try {
                    sumMap = jdbcTemplate.queryForMap(sqlSum);
                } catch (BadSqlGrammarException e) {
                    BusinessException.throwError("sql格式错误，原因：%s", e != null ? e.getMessage() :"未知原因");
                } catch (DataAccessException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    BusinessException.throwError("sql查询失败，原因：%s", e != null ? e.getMessage() :"未知原因");
                }


                if (sumMap != null) {
                    Map<String, Object> sumRow = Maps.newHashMap();
                    sumRow.put("field", "datatotal");
                    sumRow.put("label", "总记录");
                    sumRow.put("sum", sumMap.get("countsum"));
                    countSum = Integer.parseInt(sumMap.get("countsum") + "");
                    result.sumData.add(sumRow);
                    for (GridField gridField : gridFields) {
                        if (null == gridField.getFlagTotalRow() || !gridField.getFlagTotalRow()) continue;
                        ;
                        sumRow = Maps.newHashMap();
                        sumRow.put("field", gridField.getField());
                        sumRow.put("label", "总" + gridField.getLabel());

                        sumRow.put("sum", sumMap.get(gridField.getField()));
                        result.sumData.add(sumRow);
                    }
                }
            }
        }

        // 构建分页SQL
        if (forcePaging && (config.getFlagPaging() != null && config.getFlagPaging())) {

            SqlInfo sqlInfo = SqlParserUtils.getOptimizeCountSql(true, null, selectSql);
           /* Long totalCount = jdbcTemplate.query(sqlInfo.getSql(), ps -> {
                sqlUtils.fillParameters(ps, handledParams);
            }, rs -> rs.next() ? rs.getLong(1) : 0);*/
            result.setTotalCount(countSum);
            log.debug("=======================query total count sql=======================");
            log.debug("SQL: {}", sqlInfo.getSql());
            log.debug("Params: {}", handledParams);
            log.debug("=======================query total count sql=======================");
            if (countSum == 0) {
                result.setData(Collections.emptyList());
                return result;
            }

            int currPage = Integer.parseInt((String) params.getOrDefault("currPage", "1"));
            int pageSize = Integer.parseInt((String) params.getOrDefault("pageSize", "10"));

            if (params != null && !UtilCommon.strIsNull((String) params.get("orderBy"))) {
                //order by bus_key desc LIMIT 0,13 )tml
                //包含用户排序字段 则去掉数据源中的排序字段
                int orderByindex = selectSql.lastIndexOf("order by");
                if (orderByindex != -1) {
                    String orderType = "asc";
                    if (selectSql.lastIndexOf("desc") != -1) {
                        orderType = "desc";
                    }
                    int orderTypeIndex = selectSql.lastIndexOf(orderType);
                    selectSql = selectSql.substring(0, orderByindex) + " order by  " + params.get("orderBy") + selectSql.substring(orderTypeIndex + orderType.length(), selectSql.length());
                } else {
                    selectSql += " " + " order by  " + params.get("orderBy");
                }
            }

            Page page = new Page(currPage, pageSize);
            DialectModel model = DialectFactory.buildPaginationSql(page, selectSql, DbType.MYSQL, MySqlDialect.class.getName());
            String pagingSql = model.getDialectSql().replaceAll("LIMIT \\?,\\?",
                    String.format("LIMIT %d,%d", page.offset(), page.getSize())
            );
            selectSql = pagingSql;
        } else {
            if (params != null && !UtilCommon.strIsNull((String) params.get("orderBy"))) {
                //order by bus_key desc LIMIT 0,13 )tml
                //包含用户排序字段 则去掉数据源中的排序字段
                int orderByindex = selectSql.lastIndexOf("order by");
                if (orderByindex != -1) {
                    String orderType = "asc";
                    if (selectSql.lastIndexOf("desc") != -1) {
                        orderType = "desc";
                    }
                    int orderTypeIndex = selectSql.lastIndexOf(orderType);
                    selectSql = selectSql.substring(0, orderByindex) + " order by  " + params.get("orderBy") + selectSql.substring(orderTypeIndex + orderType.length(), selectSql.length());
                } else {
                    selectSql += " " + " order by  " + params.get("orderBy");
                }
            }
        }


        List<Map<String, Object>> data = jdbcTemplate.query(selectSql, ps -> {
            sqlUtils.fillParameters(ps, handledParams);
        }, (rs, rowNum) -> {
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();
            Map<String, Object> map = Maps.newHashMapWithExpectedSize(columnCount);

            for (int i = 1; i <= columnCount; i++) {
                if (rs.getObject(i) == null) {
                    map.put(metaData.getColumnLabel(i), "");
                    continue;
                }
                ;
                ;
                if (metaData.getColumnTypeName(i).equalsIgnoreCase("DATETIME") && StringUtils.isNotBlank(rs.getObject(i).toString())) {
                    map.put(metaData.getColumnLabel(i), DateUtils.format(new Date(rs.getTimestamp(i).getTime()), "yyyy-MM-dd HH:mm:ss"));
                } else {
                    map.put(metaData.getColumnLabel(i), rs.getObject(i));
                }
            }
            return map;
        });

        result.setData(data);
        result.setTotalCount(result.getTotalCount() == null ? data.size() : result.getTotalCount());
        log.debug("=======================query data sql=======================");
        log.debug("SQL: {}", selectSql);
        log.debug("Params: {}", handledParams);
        log.debug("=======================query data sql=======================");

        return result;

    }


    @Override
    public List<Map<String, Object>> sqlParse(String sql, String datasourceId, Map<String, Object> params) {
        if (StringUtils.isBlank(sql) || StringUtils.isBlank(datasourceId)) {
            throw new BusinessException("参数错误，请确认");
        }

        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.setFetchSize(0);
        jdbcTemplate.setMaxRows(0);


        NamedParamSqlUtils sqlUtils = new NamedParamSqlUtils();
        String selectSql = sql;

        // 对查询SQL进行 模板渲染
        selectSql = FreeMarkers.renderString(selectSql, params);
        selectSql = sqlUtils.parseSql(selectSql);

        Map<String, Object> handledParams = getHandledParams(sqlUtils, params);

        IPage page = new Page(1, 1);
        DialectModel model = DialectFactory.buildPaginationSql(page, selectSql, DbType.MYSQL, MySqlDialect.class.getName());
        String pagingSql = model.getDialectSql().replaceAll("LIMIT \\?,\\?", String.format("LIMIT %d,%d", 0, 1));
        selectSql = pagingSql;

        List<Map<String, Object>> result = Lists.newArrayList();
        jdbcTemplate.query(selectSql, ps -> {
            sqlUtils.fillParameters(ps, handledParams);
        }, rs -> {
            ResultSetMetaData metaData = rs.getMetaData();
            int columnCount = metaData.getColumnCount();

            for (int i = 1; i <= columnCount; i++) {
                Map<String, Object> map = Maps.newHashMapWithExpectedSize(columnCount);
                map.put("columnLabel", metaData.getColumnLabel(i));
                map.put("sort", i * 10);
                result.add(map);
            }
            return null;
        });
        return result;

    }

    @Override
    public Config copy(String id, String codeNew) {

        Config raw = this.getById(id);
        if (raw == null) {
            return null;
        }
        int count = this.count(Wrappers.<Config>query().eq("code", codeNew));
        if (count > 0) {
            throw new BusinessException("该图表标识【%s】已存在", codeNew);
        }

        final Config copy = new Config();
        BeanUtils.copyProperties(raw, copy);
        copy.setName(raw.getName() + "-副本").setCode(codeNew).setId(null);
        this.save(copy);

        List<GridField> gridFields = reportGridFieldService.list(Wrappers.<GridField>query().eq("report_id", raw.getId()));
        List<ChartField> chartFields = reportChartFieldService.list(Wrappers.<ChartField>query().eq("report_id", raw.getId()));

        gridFields.forEach(o -> o.setReportId(copy.getId()).setId(null));
        chartFields.forEach(o -> o.setReportId(copy.getId()).setId(null));
        if (!gridFields.isEmpty()) {
            reportGridFieldService.saveBatch(gridFields);
        }
        if (!chartFields.isEmpty()) {
            reportChartFieldService.saveBatch(chartFields);
        }

        CommonService.cachereport(copy.getId());
        return copy;
    }

    /**
     * 获取处理过后的参数
     *
     * @param params
     * @return
     */
    private Map<String, Object> getHandledParams(NamedParamSqlUtils sqlUtils, Map<String, Object> params) {
        if (params == null) {
            params = Maps.newHashMap();
        }
        Map<String, Object> handledParams = params;

        if (paramHandlers == null) {
            return handledParams;
        }

        // sql解析后的参数名
        Map<Integer, String> paramsMap = sqlUtils.getParamsMap();
        for (Integer index : paramsMap.keySet()) {
            String paramName = paramsMap.get(index);
            if (!params.containsKey(paramName)) {
                params.put(paramName, null);
            }
        }

        for (String key : params.keySet()) {
            for (ParamHandler handler : paramHandlers) {
                if (handler.getNeedHandleFields().contains(key)) {
                    handledParams.put(key, handler.handle(key, params.get(key)));
                }
            }
        }
        return handledParams;
    }

    /**
     * sql提取的结果
     */
    @Data
    public static class FetchResult {
        private List<Map<String, Object>> data;
        private List<Map<String, Object>> sumData;
        private Long totalCount;
        //初始化查询日期字段
        private String initDateQueryField;
        //初始化查询日期 开始时间
        private String initDateQueryStart;
        //初始化查询日期 结束时间
        private String initDateQueryEnd;
        //初始化查询日期 年份或者月份
        private String initDateQuery;
    }

    /**
     * 查询前置方法，执行前置方法，替换数据源中的  %filterSql%
     *
     * @Description：${description}
     */
    private String beforeQuery(Config config, Map<String, Object> param) {
        String sqlNew = config.getDataSql();
        logger.debug("ConfigServiceImpl.beforeQuery.sqlOld={}", sqlNew);
        //有前置方法
        if (StringUtils.isNotBlank(config.getPreFun())) {
            Map param2 = new LinkedHashMap();
            param2.putAll(param);
            try {
                sqlNew = SpringUtils.invokeMethod(BeforeReport.class, config.getPreFun(), sqlNew, param2) + "";
            } catch (Exception e) {
                e.printStackTrace();
                throw new BusinessException("执行前置方法%s失败，原因:%s", config.getPreFun(), e.getMessage());
            }
        }
        //替换数据源中的  %filterSql%
        sqlNew = sqlNew.replaceAll("%filterSql%", " ");
        logger.debug("ConfigServiceImpl.beforeQuery.sqlNew={}", sqlNew);
        return sqlNew;
    }

    @Override
    public Map<String, Object> fetchDataForPrint(String id, Map<String, Object> params) throws Exception {
        return this.fetchData(id, false, params);
    }

}
